#ifndef SYLAR_SCHEDULER_H__
#define SYLAR_SCHEDULER_H__

#include "thread.h"
#include "fiber.h"
#include "config.h"
#include "thread.h"
#include "macro.h"
#include "util.h"
#include <memory>
#include <list>
#include <vector>

namespace sylar{

class Scheduler{
public:
    typedef std::shared_ptr<Scheduler> ptr;
    typedef Mutex MutexType;
    /**
     * @brief 构造函数
     * @param threads 线程数量
     * @param use_caller 是否使用当前调用线程
     * @param name 协程调度器的名称
     */
    Scheduler(size_t threads = 1, bool use_caller = true, const std::string& name = "");
    virtual ~Scheduler();

    const std::string& getName() const {return m_name;}
    
    /**
     * @brief 返回当前的协程调度器
     */
    static Scheduler* GetThis();

    /**
     * @brief 返回当前协程调度器的调度协程
     */
    static Fiber* GetMainFiber();

    void start();
    void stop();

    /**
     * @brief 协程调度(单个协程)
     * @param fc 需要调度的协程或者cb函数
     * @param thread 执行该协程的线程id, -1表示任意线程
     */
    template<class FiberOrCb>
    void schedule(FiberOrCb fc, int thread = -1){
        bool need_tickle = false;
        {
            MutexType::Lock lock(m_mutex);
            need_tickle = scheduleNolock(fc, thread);    
        }
        if(need_tickle) {
            tickle();
        }
    }
    /**
     * @brief 协程调度(批量调度)
     * @param begin 容器起始迭代器
     * @param end 容器结束迭代器
     */
    template<class InputIterator>
    void schedule(InputIterator begin, InputIterator end){
        bool need_tickle = false;
        {
            MutexType::Lock lock(m_mutex);
            while(begin != end){
                need_tickle = scheduleNolock((&*begin), -1) | need_tickle;
				++begin;
            }
        }
        if(need_tickle) tickle();
    }
protected:
    /**
     * @brief  通知协程调度器有任务到来
     */
    virtual void tickle();
    /**
     * @brief 协程调度主函数
     */
    void run();
    /**
     * @brief 协程调度器是否可以结束. 
     */
    virtual bool stopping();
    /**
     * @brief  设置当前的协程调度器
     */
    void setThis();
    /**
     * @brief 无任务可调度 执行idle协程
     */
    virtual void idle();

    bool hasIdleThreads(){ return m_idleThreadCount > 0;}

private:
    /**
     * @brief 协程调度启动(无锁)
     * 将事件放入协程的消息队列
     */
    template<class FiberOrCb>
    bool scheduleNolock(FiberOrCb fc, int thread){
        bool need_tickle = m_fibers.empty();
        FiberAndThread ft(fc, thread);
        if(ft.fiber || ft.cb){
            m_fibers.push_back(ft);
        }
        return need_tickle;
    }

private:
    /**
     * @brief 协程或函数 可以理解为一个事件
     */
    struct FiberAndThread{
        Fiber::ptr fiber;
        std::function<void()> cb;
        int thread;

        FiberAndThread(Fiber::ptr f, int thr)
            :fiber(f), thread(thr){
        }
        FiberAndThread(Fiber::ptr* f, int thr)
            :thread(thr){
            fiber.swap(*f);
        }
        FiberAndThread(std::function<void()> f, int thr)
            :cb(f), thread(thr){
        }
        FiberAndThread(std::function<void()>* f, int thr)
            :thread(thr){
            cb.swap(*f);
        }
        FiberAndThread()
            :thread(-1){
        }
        void reset() {
            fiber = nullptr;
            cb = nullptr;
            thread = -1;
        }
    };


private:
    MutexType m_mutex;
    std::vector<Thread::ptr> m_threads;  //线程池
    std::list<FiberAndThread> m_fibers; //协程的消息队列
    Fiber::ptr m_rootFiber;             //use_caller为true时有效 调度协程
    std::string m_name;                 //协程调度器名称

protected:
    std::vector<int> m_threadIds;    //记录所有的线程id的数组
    size_t m_threadCount = 0;       // 线程数量
    std::atomic<size_t> m_activeThreadCount = {0};    //工作线程数量
    std::atomic<size_t> m_idleThreadCount = {0};      //空闲线程数量
    bool m_stopping = true;         //是否正在停止
    bool m_autoStop = false;        //是否自动停止
    int m_rootThread = 0;           //使用use_caller时的主线程id

};

}   //namespace sylar
#endif